package com.cl.pile.rule.process;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cl.pile.rule.DTO.RuleResult;
import com.cl.pile.rule.filter.*;
import com.cl.pile.rule.func.*;
import com.cl.pile.rule.pojo.RuleItem;
import com.cl.pile.rule.utils.Calculator;
import com.cl.pile.rule.utils.DbUtil;
import com.cl.pile.rule.utils.HttpUtil;
import com.cl.pile.rule.utils.JsonConvertUtil;
import info.debatty.java.stringsimilarity.RatcliffObershelp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.cl.pile.rule.config.RuleConstant.*;

/**
 * @author chenyitao
 * @date 2021/4/26
 */
@Slf4j
@Component
public class RuleMatcher {

    private static final Map<String, String> ruleCache = new ConcurrentHashMap<>();
    private static int weight = 0;
    private static final Map<String, IFilterOperation> filterOperationMap = new HashMap<>();
    private static final Map<String, IFunc> funcMap = new HashMap<>();
    /**
     * \${\w[\w.\[\]]+} -> ${a.b} ${a.b.c[0]}
     */
    private static final Pattern varPattern = Pattern.compile("\\$\\{\\w[\\w.\\[\\]]*?}");
    private static final Pattern funcPattern = Pattern.compile("\\$(\\w+)\\((\\$\\{\\w[\\w.\\[\\]]*?\\})(,\\{.+\\})?\\)");
    private final JsonConvertUtil jsonConvertUtil;
    boolean isForward = false;
    //    private final DbUtil dbUtil;
    @Autowired(required = false)
    private DbUtil dbUtil;
    @Value("${spring.datasource.driver-class-name:}")
    private String driver;
    @Value("${spring.datasource.url:}")
    private String dbUrl;
    @Value("${spring.datasource.username:}")
    private String dbUsername;
    @Value("${spring.datasource.password:}")
    private String dbPassword;

    private final AtomicInteger updateCount = new AtomicInteger(0);
    private final AtomicInteger updateThread = new AtomicInteger(0);
    private final BlockingQueue<Map<String, String>> qkWriteList = new LinkedBlockingQueue<>(1600000);
    private final ExecutorService pool = Executors.newCachedThreadPool();


    public RuleMatcher() {
        this.dbUtil = null;
        this.jsonConvertUtil = new JsonConvertUtil();
        initFilterOperationMap();
        initFuncMap();
    }

    public static Map<String, String> getRuleCache() {
        return ruleCache;
    }

    public static int getWeight() {
        return weight;
    }


    private static void initFuncMap() {
        funcMap.put("sum", new SumFunc());
        funcMap.put("avg", new AvgFunc());
        funcMap.put("max", new MaxFunc());
        funcMap.put("min", new MinFunc());
    }

    private void initFilterOperationMap() {
        filterOperationMap.put("=", new EqFilterOperation());
        filterOperationMap.put("contains", new ContainsFilterOperation());
        filterOperationMap.put("in", new InFilterOperation());
        filterOperationMap.put("inContains", new InContainsFilterOperation());
        filterOperationMap.put("inContainsAnd", new InContainsAndOperation());
        filterOperationMap.put("notContainsOr", new NotContainsOrOperation());
        filterOperationMap.put("regex", new RegexFilterOperation());
        filterOperationMap.put("dateGt", new DateGtFilterOperation());
        filterOperationMap.put("dateLt", new DateLtFilterOperation());
        filterOperationMap.put("dateEq", new DateEqFilterOperation());
        filterOperationMap.put("endWith", new EndWithFilterOperation());
        filterOperationMap.put(">", new GtFilterOperation());
        filterOperationMap.put(">=", new GteFilterOperation());
        filterOperationMap.put("<", new LtFilterOperation());
        filterOperationMap.put("<=", new LteFilterOperation());
        filterOperationMap.put("!=", new NotEqFilterOperation());
        filterOperationMap.put("notContains", new NotContainsFilterOperation());
        filterOperationMap.put("listOverlap", new ListOverlapOperation());
        filterOperationMap.put("listAllOverlap", new ListAllOverlapOperation());
        filterOperationMap.put("listNoOverlap", new ListNoOverlapOperation());
    }

    public boolean matchRuleByMap(Map<String, Object> dataMap, JSONObject ruleJson,
                                  JSONObject cpJson, List<String> errorList, List<String> tipsList) {
        return execMatchRule(JsonConvertUtil.convertMapToJson(dataMap), ruleJson, cpJson, errorList, tipsList);
    }

    public static boolean matchRuleByMap(Map<String, Object> dataMap, JSONObject ruleJson,
                                         JSONObject cpJson, List<String> errorList, List<String> tipsList, String dbCode) {
        return execMatchRule(dataMap, ruleJson, cpJson, errorList, tipsList, dbCode);
    }

    public static boolean execMatchRule(Object dataObj, JSONObject ruleJson,
                                        JSONObject cpJson, List<String> errorList, List<String> tipsList) {
        return matchRule(dataObj, ruleJson, cpJson, errorList, tipsList, null);
    }

    public static RuleResult execMatchRule(Object dataObj, JSONObject ruleJson) {
        List<String> errorList = new ArrayList<>();
        List<String> tipsList = new ArrayList<>();
        JSONObject cpJson = new JSONObject();
        boolean match = matchRule(dataObj, ruleJson, cpJson, errorList, tipsList, null);

        return new RuleResult(errorList, tipsList, cpJson, match);

    }

    public static boolean execMatchRule(Object dataObj, JSONObject ruleJson,
                                        JSONObject cpJson, List<String> errorList, List<String> tipsList, String dbCode) {
//        isForward = !ruleJson.toJSONString().contains("error");
        return matchRule(dataObj, ruleJson, cpJson, errorList, tipsList, dbCode);
    }

    public static boolean matchRule(Object dataObj, JSONObject ruleJson,
                                    JSONObject cpJson, List<String> errorList, List<String> tipsList, String dbCode) {
        if (ruleJson == null) {
            return true;
//            return false;
        }
//        int levelWeight = 0;
        boolean success = false;
        if (ruleJson.containsKey(IF)) {
            JSONObject ifRuleJson = ruleJson.getJSONObject(IF);
//            JSONObject tempConditionJson = ifRuleJson.getJSONObject("condition");
//            if(tempConditionJson.getInteger("weight") != null) {
//                levelWeight = tempConditionJson.getInteger("weight");
//            }
            JSONObject ifCpJson = new JSONObject();
            JSONObject conditionJson = new JSONObject();
            JSONObject messageJson = new JSONObject();
            messageJson.put("message", "分支未被执行");
            if (matchRule(dataObj, ifRuleJson.getJSONObject(CONDITION), conditionJson, errorList, tipsList, dbCode)) {
                JSONObject trueCpJson = new JSONObject();
                success = matchRule(dataObj, ifRuleJson.getJSONObject(TRUE), trueCpJson, errorList, tipsList, dbCode);
                ifCpJson.put(TRUE, trueCpJson);
                ifCpJson.put(FALSE, messageJson);
            } else {
                JSONObject falseCpJson = new JSONObject();
                success = matchRule(dataObj, ifRuleJson.getJSONObject(FALSE), falseCpJson, errorList, tipsList, dbCode);
                if (ifRuleJson.getJSONObject(FALSE) == null) {
                    success = false;
                }
                ifCpJson.put(FALSE, falseCpJson);
                ifCpJson.put(TRUE, messageJson);
            }
            ifCpJson.put(CONDITION, conditionJson);
            cpJson.put(IF, ifCpJson);
        } else {
            if (ruleJson.containsKey(AND)) {
                JSONArray andList = ruleJson.getJSONArray(AND);
                JSONArray andArray = new JSONArray();
                success = matchRule(dataObj, andList, true, andArray, errorList, tipsList, dbCode);
                cpJson.put(AND, andArray);
            }
            if (ruleJson.containsKey(OR)) {
                JSONArray orList = ruleJson.getJSONArray(OR);
                JSONArray orArray = new JSONArray();
                success = matchRule(dataObj, orList, false, orArray, errorList, tipsList, dbCode);
                cpJson.put(OR, orArray);
            }
        }
//        if (success) {
//            weight += levelWeight;
//        }
        return success;
    }


    private static boolean matchRule(Object dataObj, JSONArray rules, boolean isAnd,
                                     JSONArray array, List<String> errorList, List<String> tipsList, String dbCode) {
        if (rules == null || rules.isEmpty()) {
            return true;
        }
        int successIndex = 0;
        for (Object obj : rules) {
            JSONObject item;
            if (obj instanceof JSONObject) {
                item = (JSONObject) obj;
            } else {
                item = JSONObject.parseObject(JSONObject.toJSONString(obj));
            }
            if (item.containsKey("value") && StringUtils.isNotBlank(item.getString("value")) && item.getString("value").charAt(0) == '@') {
                String valueSource = item.getString("value");
                String ruleStr = valueSource.replace("@", "").split(";")[0];
                if (ruleCache.containsKey(ruleStr)) {
                    String rule_expression_json = ruleCache.get(ruleStr);
                    if (valueSource.contains(";")) {
                        String[] values = valueSource.split(";");
                        for (int i = 1; i < values.length; i++) {
                            rule_expression_json = rule_expression_json.replace("{#" + (i - 1) + "}", values[i]);
                        }
                    }
                    item = JSONObject.parseObject(rule_expression_json);
                }
//                else {
//                    try {
//                        Class.forName(driver);
//                        String url = dbUrl;
//                        String username = dbUsername;
//                        String password = dbPassword;
//                        Connection connection = DriverManager.getConnection(url, username, password);
//                        Statement statement = connection.createStatement();
//                        String sql = "select rule_expression_json from ks_rule where rule_name='" + ruleStr + "'";
//                        ResultSet resultSet = statement.executeQuery(sql);
//                        while (resultSet.next()) {
//                            String rule_expression_json = resultSet.getString("rule_expression_json");
//                            RuleMatcher.ruleCache.put(ruleStr, rule_expression_json);
//                            if (valueSource.contains(";")) {
//                                String[] values = valueSource.split(";");
//                                for (int i = 1; i < values.length; i++) {
//                                    rule_expression_json = rule_expression_json.replace("{#" + (i - 1) + "}", values[i]);
//                                }
//                            }
//                            item = JSONObject.parseObject(rule_expression_json);
//                        }
//                        resultSet.close();
//                        statement.close();
//                        connection.close();
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                }

            }
            if (item.containsKey(AND) || item.containsKey(OR) || item.containsKey(IF)) {
                JSONObject childCpJson = new JSONObject();
                if (matchRule(dataObj, item, childCpJson, errorList, tipsList, dbCode)) {
                    successIndex++;
                }
                array.add(childCpJson);
            } else if (item.containsKey(TRUE) || item.containsKey(FALSE) || item.containsKey(CONDITION)) {
                log.error("无效格式 {}", item.toJSONString());
            } else {
                // 优先处理单个规则
                RuleItem ruleItem = item.toJavaObject(RuleItem.class);
//                Object value = getValue(ruleItem.getField(), dataObj,
//                        JsonConvertUtil.getmFieldValue(ruleItem.getField(), dataObj), dbCode);
                Object value = getValue(ruleItem.getField(), dataObj, JsonConvertUtil.getFieldValue(ruleItem.getField(), dataObj), dbCode);
                String matchValue = String.valueOf(getValue(ruleItem.getValue(), dataObj, ruleItem.getValue(), dbCode));

                boolean match = false;
                if (filterOperationMap.containsKey(ruleItem.getOp())) {
                    if (filterOperationMap.get(ruleItem.getOp()).filterMatch(value, matchValue)) {
                        successIndex++;
                        match = true;
                    }
                } else {
                    throw new RuntimeException("无效操作符 " + ruleItem.getOp());
                }


                if (ruleItem.getField().contains("#checkInOver10Day")) {
                    value = ruleItem.getValue();
                }
                String originalValue = String.valueOf(value);
                if (value != null && String.valueOf(value).length() > 200) {
                    value = String.valueOf(value).substring(0, 50);
                }
                JSONObject cpItem = new JSONObject();
                cpItem.put("weight", ruleItem.getWeight());
                cpItem.put("field", ruleItem.getField());
                cpItem.put("value", ruleItem.getValue());
                cpItem.put("op", ruleItem.getOp());
                cpItem.put("compare", String.format("%s %s %s",
                        ruleItem.getField(), ruleItem.getOp(), ruleItem.getValue()));
                cpItem.put("valueCompare", String.format("%s %s %s",
                        value, ruleItem.getOp(), matchValue));
                cpItem.put("match", match);

                if (!match && ruleItem.getWeight() != null) {
                    weight += Integer.parseInt(ruleItem.getWeight());
                }

                if (StringUtils.isNotBlank(ruleItem.getError())) {
                    cpItem.put("error", ruleItem.getError());
                }
                String tips = ruleItem.getTips();
                if (match && StringUtils.isNotBlank(tips)) {
                    if (tips.contains("{$")) {
                        List<String> matchKeyword = new ArrayList<>();
                        String keywords = tips.substring(tips.indexOf("{$") + 2, tips.indexOf("}"));
                        String[] keywordsArray;
                        if (keywords.contains(",")) {
                            keywordsArray = keywords.split(",");
                        } else {
                            keywordsArray = new String[]{keywords};
                        }
                        Arrays.stream(keywordsArray)
                                .filter(keyword -> String.valueOf(originalValue).contains(keyword))
                                .forEach(matchKeyword::add);
                        if (!matchKeyword.isEmpty()) {
                            String res = tips.replace("{$" + keywords + "}", matchKeyword.toString());
                            cpItem.put("tips", res);
                            tipsList.add(res);
                        }
                    } else {
                        tipsList.add(ruleItem.getTips());
                    }
                }
                if (!match && StringUtils.isNotBlank(ruleItem.getError())) {
                    // 未匹配添加错误原因
                    if (errorList != null) {
                        errorList.add(ruleItem.getError());
                    }
                }
                array.add(cpItem);

                // 短路特性
                if (!isAnd && match) {
                    // or 条件下存在匹配成功项
                    break;
//                } else if (isAnd && !match && StringUtils.isNotBlank(ruleItem.getError())) {
                } else if (isAnd && !match) {
                    // and 条件下存在匹配不成功项并且设置了错误信息
                    break;
                }
            }
        }
        if (isAnd) {
            return successIndex == rules.size();
        } else {
            return successIndex > 0;
        }
    }

    public String varToValue(String v, Map<String, Object> dataObj) {
        JSONObject data = jsonConvertUtil.convertMapToJson(dataObj);
        Matcher varMatcher = varPattern.matcher(v);
        while (varMatcher.find()) {
            String group = varMatcher.group();
            String mField = group.replaceAll("[${|}]", "");
            String value = jsonConvertUtil.getmFieldValue(mField, data);
            if (StringUtils.isNotBlank(value)) {
                v = v.replace(group, value);
            }
        }
        return v;

    }

    private static Object handleGetValue(String v, Object dataObj, Object dv, int repSizeParam, String dbCode) {
        AtomicInteger repSize = new AtomicInteger(repSizeParam);
//        Matcher funcMatcher = funcPattern.matcher(v);
//        while (funcMatcher.find()) {
//            String func = funcMatcher.group(1);
//            String var = funcMatcher.group(2);
//            String rule = funcMatcher.group(3);
//
//            if (funcMap.containsKey(func)) {
//                JSONObject ruleJson = null;
//                if (rule != null) {
//                    // 跳过 , 符号
//                    ruleJson = JSONObject.parseObject(rule.substring(1));
//                }
//                var = var.replaceAll("[${|}]", "");
//                List<Object> data = new ArrayList<>();
//                JsonConvertUtil.getResultFromJson(dataObj, var, data);
//                Object value = funcMap.get(func).func(data, var, dataObj, ruleJson);
//                v = String.valueOf(value);
//                repSize.incrementAndGet();
//            }
//        }

        Matcher varMatcher = varPattern.matcher(v);
        while (varMatcher.find()) {
            String group = varMatcher.group();
            String mField = group.replaceAll("[${|}]", "");
            String value = JsonConvertUtil.getmFieldValue(mField, dataObj);
            v = v.replace(group, value);
            repSize.incrementAndGet();
        }
        v = getNumber(v, repSize);
        v = getIDCardAge(v, repSize);
        v = getIDCardDaysUntilNow(v, repSize);
        v = calcDate(v, repSize);
        v = getIdCardDate(v, repSize);
        v = getLength(v, repSize);
        v = getSimilarity(v, repSize);
//        v = getHistoryCrime(v, repSize, dataObj, dbCode);
//        v = mysqlFetchFunction(v, repSize, dbCode);
//        v = mysqlExecuteFunction(v, repSize, dbCode);
//        v = checkInOver10Day(v, dataObj, repSize);
        v = apiFunction(v, repSize);
        if (repSize.get() > 0) {
            try {
                Matcher matcher = Calculator.getDateMatcherFromString(v);
                if (matcher.find()) {
                    return Calculator.calculateDate(v);
                }
                return Calculator.calculate(v);
            } catch (Exception e) {
                log.error(e.getMessage());
            }
            return v;
        } else {
            return dv;
        }

    }

    private static String apiFunction(String v, AtomicInteger repSize) {
        Matcher matcher = Pattern.compile("#apiFunction\\((\\{.+})\\)").matcher(String.valueOf(v));
        while (matcher.find()) {
            String group = matcher.group();
            String value = matcher.group(1);
            JSONObject apiParam = JSONObject.parseObject(value);
            String url = apiParam.getString("url");
            String method = apiParam.getString("method");
            JSONObject param = apiParam.getJSONObject("param");
            if (method.equalsIgnoreCase("get")) {
                value = HttpUtil.okhttpGetString(url, param);
            } else if (method.equalsIgnoreCase("post")) {
                value = HttpUtil.okhttpPostString(url, param);
            }
            if (StringUtils.isNotBlank(value)) {
                v = v.replace(group, value);
                repSize.incrementAndGet();
            }
        }
        return v;
    }

    private static String getIdCardDate(String v, AtomicInteger repSize) {
        Matcher matcher = Pattern.compile("#getIDCardDate\\((\\w+)\\)").matcher(String.valueOf(v));
        while (matcher.find()) {
            String group = matcher.group();
            String value = matcher.group(1);
            value = value.substring(6, 10) + "-" + value.substring(10, 12) + "-" + value.substring(12, 14);
            if (StringUtils.isNotBlank(value)) {
                v = v.replace(group, value);
                repSize.incrementAndGet();
            }
        }
        return v;
    }

    private static String getLength(String v, AtomicInteger repSize) {
        Matcher matcher = Pattern.compile("#getLength\\((.+)\\)").matcher(String.valueOf(v));
        while (matcher.find()) {
            String group = matcher.group();
            String value = matcher.group(1);
            value = String.valueOf(value.length());
            if (StringUtils.isNotBlank(value)) {
                v = v.replace(group, value);
                repSize.incrementAndGet();
            }
        }
        return v;
    }

    private static String getNumber(String v, AtomicInteger repSize) {
        Pattern numberPattern = Pattern.compile("\\d+");
        Matcher matcher = Pattern.compile("#getNumber\\((.+)\\)").matcher(String.valueOf(v));
        while (matcher.find()) {
            StringBuilder newValue = new StringBuilder();
            String group = matcher.group();
            String value = matcher.group(1);
            Matcher numberPatternMatcher = numberPattern.matcher(value);
            while (numberPatternMatcher.find()) {
                newValue.append(numberPatternMatcher.group());
            }
            value = newValue.toString();
            if (StringUtils.isNotBlank(value)) {
                v = v.replace(group, value);
                repSize.incrementAndGet();
            }
        }
        return v;
    }

    private static String getSimilarity(String v, AtomicInteger repSize) {
        Matcher matcher = Pattern.compile("#getSimilarity\\((.+)\\)").matcher(String.valueOf(v));
        while (matcher.find()) {
            String group = matcher.group();
            String value = matcher.group(1);

            String[] valueArray = value.split(",");
            String cp1 = valueArray[0];
            String cp2 = valueArray[1];

            for (int i = 2; i < valueArray.length; i++) {
                cp1 = cp1.replaceAll(valueArray[i], "");
                cp2 = cp2.replaceAll(valueArray[i], "");
            }
            RatcliffObershelp l = new RatcliffObershelp();

            value = String.valueOf(l.similarity(cp1, cp2));
            if (StringUtils.isNotBlank(value)) {
                v = v.replace(group, value);
                repSize.incrementAndGet();
            }
        }
        return v;
    }

    private static String getIDCardDaysUntilNow(String v, AtomicInteger repSize) {
        Matcher matcher = Pattern.compile("#getIDCardDaysUntilNow\\((\\w+)\\)").matcher(String.valueOf(v));
        while (matcher.find()) {
            String group = matcher.group();
            String value = matcher.group(1);
            value = value.substring(6, 10) + "-" + value.substring(10, 12) + "-" + value.substring(12, 14);
            try {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                Date idCardDate = simpleDateFormat.parse(value);
                Long days = (new Date().getTime() - idCardDate.getTime()) / (1000 * 60 * 60 * 24);
                value = String.valueOf(days);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            if (StringUtils.isNotBlank(value)) {
                v = v.replace(group, value);
                repSize.incrementAndGet();
            }
        }
        return v;

    }

    private static String getIDCardAge(String v, AtomicInteger repSize) {
        Matcher matcher = Pattern.compile("#getIDCardAge\\((\\w+)\\)").matcher(String.valueOf(v));
        while (matcher.find()) {
            String group = matcher.group();
            String value = matcher.group(1);
            value = value.substring(6, 10) + "-" + value.substring(10, 12) + "-" + value.substring(12, 14);
            try {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                Date idCardDate = simpleDateFormat.parse(value);
                Long days = (new Date().getTime() - idCardDate.getTime()) / (1000 * 60 * 60 * 24) / 365;
                value = String.valueOf(days);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            if (StringUtils.isNotBlank(value)) {
                v = v.replace(group, value);
                repSize.incrementAndGet();
            }
        }
        return v;

    }

    private static String calcDate(String v, AtomicInteger repSize) {
        Matcher matcher = Pattern.compile("#calcDate\\(([\\s\\S]+)\\)").matcher(String.valueOf(v));
        while (matcher.find()) {
            String group = matcher.group();
            String value = matcher.group(1);

            try {
                String[] param = value.split(",");
                String dateStr = param[0];
                String type = param[1];
                String addValue = param[2];
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                Date date = simpleDateFormat.parse(dateStr);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(date);

                switch (type) {
                    case "month":
                        calendar.add(Calendar.MONTH, Integer.parseInt(addValue));
                        break;
                    case "year":
                        calendar.add(Calendar.YEAR, Integer.parseInt(addValue));
                        break;
                    case "day":
                        calendar.add(Calendar.DATE, Integer.parseInt(addValue));
                        break;
                }

                value = simpleDateFormat.format(calendar.getTime());
            } catch (ParseException e) {
                e.printStackTrace();
            }
            if (StringUtils.isNotBlank(value)) {
                v = v.replace(group, value);
                repSize.incrementAndGet();
            }
        }
        return v;
    }

//    private static String mysqlFetchFunction(String v, AtomicInteger repSize, String dbCode) {
//        Matcher matcher = Pattern.compile("#mysqlFetchFunction\\((.+)\\)").matcher(String.valueOf(v));
//        if (matcher.find()) {
//            String group = matcher.group();
//            String value = matcher.group(1);
//            value = JSONObject.toJSONString(dbUtil.fetchSQL(dbCode, value));
//            if (StringUtils.isNotBlank(value)) {
//                v = v.replace(group, value);
//                repSize.incrementAndGet();
//            }
//        }
//        return v;
//    }

//    private static String mysqlExecuteFunction(String v, AtomicInteger repSize, String dbCode) {
//        Matcher matcher = Pattern.compile("#mysqlExecuteFunction\\((.+)\\)").matcher(String.valueOf(v));
//        if (matcher.find()) {
//            String group = matcher.group();
//            String value = matcher.group(1);
//            dbUtil.executeSQL(dbCode, value);
//            if (StringUtils.isNotBlank(value)) {
//                v = v.replace(group, value);
//                repSize.incrementAndGet();
//            }
//        }
//        return v;
//    }

//    private static String checkInOver10Day(String v, Object dataObj, AtomicInteger repSize) {
//        Matcher checkInOver10DayMatcher = Pattern.compile("#checkInOver10Day\\{}").matcher(String.valueOf(v));
//        while (checkInOver10DayMatcher.find()) {
//            String group = checkInOver10DayMatcher.group();
//            String value = group.replaceAll("[#checkInOver10Day\\{|}]", "");
//            JSONObject jsonObject = (JSONObject) (JSONObject.toJSON(dataObj));
//            String zjhm = jsonObject.getString("zjhm");
//            String bgsj = jsonObject.getString("bgsj");
//            List<Map<String, Object>> bgqk = dbUtil.fetchSQL(null, "select count(1) as count from data_source_sq_rcbgqk where zjhm='" + zjhm + "' and bgsj<STR_TO_DATE('" + bgsj + "','%Y-%m-%d') and bgsj>ADDDATE(STR_TO_DATE('" + bgsj + "','%Y-%m-%d'),-10);\n");
//            Long bgqkCount = (Long) bgqk.get(0).get("count");
//            if (bgqkCount < 1) {
//                List<Map<String, Object>> qjqk = dbUtil.fetchSQL(null, "select count(1) as count from data_source_sq_qjqk where zjhm='" + zjhm + "' and qjjsrq<STR_TO_DATE('" + bgsj + "','%Y-%m-%d') and qjjsrq>ADDDATE(STR_TO_DATE('" + bgsj + "','%Y-%m-%d'),-10);\n");
//                Long qjqkCount = (Long) qjqk.get(0).get("count");
//                if (qjqkCount < 1) {
//                    repSize.incrementAndGet();
//                    v = "false";
//                    return v;
//                }
//            }
////            String value = jsonConvertUtil.getFieldValue(mField, dataObj);
//            v = "true";
//            repSize.incrementAndGet();
//        }
//        return v;
//    }


//    private static String getHistoryCrime(String v, AtomicInteger repSize, Object dataObj, String dbCode) {
//        Matcher matcher = Pattern.compile("#getHistoryCrime\\{.+}").matcher(String.valueOf(v));
//        if (matcher.find()) {
//            String group = matcher.group();
//            String value = group.replace("#getHistoryCrime{", "").replace("}", "");
//            String writeField = value;
//            String writeValue = "";
//            JSONObject jsonObject = (JSONObject) (JSONObject.toJSON(dataObj));
//            if (!StringUtils.isNotBlank(jsonObject.getString("zjhm"))) {
//                return v;
//            }
//            try {
//
//                List<String> writeList = new ArrayList<>();
//                String sql = "select a.pjrq_m\n" +
//                        "from (select distinct pjrq_m\n" +
//                        "      from jd_common_history_crime\n" +
//                        "      where zjhm = '" + jsonObject.getString("zjhm") + "'\n" +
//                        "        and DATEDIFF(STR_TO_DATE(concat(pjrq_m, '-01'), '%Y-%m-%d'),\n" +
//                        "                     STR_TO_DATE(concat('" + jsonObject.getString("pjrq_m") + "', '-01'), '%Y-%m-%d')) < 0) as a\n" +
//                        "where pjrq_m not in (select pjrq_m\n" +
//                        "                     from jd_common_history_crime\n" +
//                        "                     where zjhm = '" + jsonObject.getString("zjhm") + "'\n" +
//                        "                       and doc_code = '" + jsonObject.getString("doc_code") + "'\n" +
//                        "                       and status = 0)";
//                writeList = dbUtil.fetchSQL(dbCode, sql).stream().filter(r -> r.containsKey("pjrq_m")).map(r -> String.valueOf(r.get("pjrq_m"))).collect(Collectors.toList());
//                if (!writeList.isEmpty()) {
//                    writeValue = "\\(\\'" + String.join("\\'\\)0,\\(\\'", writeList) + "\\'\\)0";
//                    String updateSQL = "update jd_common_history_crime set " + writeField + "='" + writeValue + "',clue_time=now()  where id=" + jsonObject.getString("id");
////                            + " and " + writeField + " is null";
//                    Map<String, String> map = new HashMap<>();
////                    map.put("field", writeField);
//                    map.put("value", writeValue);
//                    map.put("id", jsonObject.getString("id"));
//                    qkWriteList.add(map);
//                    dbUtil.executeSQL(dbCode, updateSQL);
//                }
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//            if (StringUtils.isNotBlank(value)) {
//                v = v.replace(group, value);
//                repSize.incrementAndGet();
//            }
//        }
//        return v;
//    }


    private static Object getValue(String v, Object dataObj, Object dv, String dbCode) {
        if (StringUtils.isBlank(v)) {
            return dv;
        }
        int count = 0;
        String tempv = v;
        while (v.contains("(") && funcMap.keySet().stream().anyMatch(r -> tempv.contains(r))) {
            count++;
            v = v.substring(0, v.indexOf(")") + 1).replace(v.substring(v.indexOf("("), v.indexOf(")") + 1), "") + handleGetValue(v.substring(v.indexOf("(") + 1, v.indexOf(")")), dataObj, dv, 0, dbCode) + v.substring(v.indexOf(")") + 1);
        }
        if (count > 0) {
            return handleGetValue(v, dataObj, dv, 1, dbCode);
//            if (v.contains("*")) {
//                String[] varray = v.split("\\*");
//                return Math.multiplyExact(Integer.parseInt(varray[0]), Integer.parseInt(varray[1]));
//            }
//            return v;
        }

        return handleGetValue(v, dataObj, dv, 0, dbCode);

    }

    public Map<String, IFilterOperation> getFilterOperationMap() {
        return filterOperationMap;
    }

    public Map<String, IFunc> getFuncMap() {
        return funcMap;
    }

    public JsonConvertUtil getJsonConvertUtil() {
        return jsonConvertUtil;
    }

}
